package com.springboot.frame.starter.tools;

import com.springboot.frame.starter.applet.pojo.AppletUserDecodeData;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.CharEncoding;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.AlgorithmParameters;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Arrays;
import java.util.Random;

/**
 * @Description 获取用户信息工具类
 * @Author xiaochen
 * @Date 2021/8/12 15:45
 */
@Slf4j
public class WxUtils {
    /**
     * 随机字符
     */
    private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    private static final Random RANDOM = new SecureRandom();

    /**
     * 微信小程序API 用户数据的解密
     *
     * @param encryptedData
     * @param sessionKey
     * @param iv
     * @return
     */
    public static AppletUserDecodeData encryptedData(String encryptedData, String sessionKey, String iv) {
        // 被加密的数据
        byte[] dataByte = Base64.decode(encryptedData);
        // 加密秘钥
        byte[] keyByte = Base64.decode(sessionKey);
        // 偏移量
        byte[] ivByte = Base64.decode(iv);
        try {
            // 如果密钥不足16位，那么就补足.  这个if 中的内容很重要
            int base = 16;
            if (keyByte.length % base != 0) {
                int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
                byte[] temp = new byte[groups * base];
                Arrays.fill(temp, (byte) 0);
                System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
                keyByte = temp;
            }
            // 初始化
            Security.addProvider(new BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
            SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
            parameters.init(new IvParameterSpec(ivByte));
            // 初始化
            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);
            byte[] resultByte = cipher.doFinal(dataByte);
            if (null != resultByte && resultByte.length > 0) {
                String result = new String(resultByte, CharEncoding.UTF_8);
                log.info("解密原串. result = {}", result);
                return WxJsonUtils.parseObject(result, AppletUserDecodeData.class);
            }
            throw new RuntimeException("解密的数据为空");
        } catch (Exception e) {
            log.error("解密失败. error = {}", e.getMessage(), e);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 微信小程序API 用户数据的签名验证
     * signature = sha1( rawData + session_key )
     *
     * @param rawData    不包括敏感信息的原始数据字符串，用于计算签名。
     * @param sessionKey
     */
    public static void verifySignature(String rawData, String sessionKey, String signature) {
        String serverSignature = SHA1.getSHA1(rawData + sessionKey);
        if (!signature.equals(serverSignature)) {
            throw new RuntimeException("数据验签不通过");
        }
    }


    /**
     * 根据流接收请求数据
     *
     * @param request
     * @return
     */
    public static String streamBodyByReceive(HttpServletRequest request) throws IOException {
        log.info("微信支付异步回调地址：{}", request.getRequestURL());
        BufferedReader reader = null;
        StringBuffer sb = new StringBuffer();
        try {
            ServletInputStream stream = request.getInputStream();
            // 获取响应
            reader = new BufferedReader(new InputStreamReader(stream));
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            throw new RuntimeException("读取微信支付接口数据流出现异常！");
        } finally {
            reader.close();
        }
        return sb.toString();
    }

    /**
     * 获取随机字符串 Nonce Str
     *
     * @return String 随机字符串
     */
    public static String generateNonceStr() {
        char[] nonceChars = new char[32];
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        return new String(nonceChars);
    }

    /**
     * 获取当前时间戳，单位秒
     *
     * @return
     */
    public static long getCurrentTimestamp() {
        return System.currentTimeMillis() / 1000;
    }

    /**
     * 获取当前时间戳，单位毫秒
     *
     * @return
     */
    public static long getCurrentTimestampMs() {
        return System.currentTimeMillis();
    }

    /**
     * 日志
     *
     * @return
     */
    public static Logger getLogger() {
        Logger logger = LoggerFactory.getLogger("wxpay java sdk  --->");
        return logger;
    }

    /**
     * debug
     *
     * @param msg
     * @param args
     */
    public static void debug(String msg, Object... args) {
        Logger log = getLogger();
        if (log.isDebugEnabled()) {
            log.debug(msg, args);
        }
    }

    /**
     * info
     *
     * @param msg
     * @param args
     */
    public static void info(String msg, Object... args) {
        Logger log = getLogger();
        if (log.isInfoEnabled()) {
            log.info(msg, args);
        }
    }

    /**
     * warn
     *
     * @param msg
     * @param args
     */
    public static void warn(String msg, Object... args) {
        Logger log = getLogger();
        if (log.isWarnEnabled()) {
            log.warn(msg, args);
        }
    }

    /**
     * error
     *
     * @param msg
     * @param args
     */
    public static void error(String msg, Object... args) {
        Logger log = getLogger();
        if (log.isErrorEnabled()) {
            log.error(msg, args);
        }
    }
}
